package cn.mill.core;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.mill.common.Node;
import cn.mill.common.Protocol;
import cn.mill.common.Strategy;
import cn.mill.common.annotation.MethodMapping;
import cn.mill.common.annotation.ServiceDefine;
import cn.mill.common.data.DataCommon;
import cn.mill.common.data.ItemArray;
import cn.mill.common.message.Message;
import cn.mill.core.modem.DefaultSpell;
import cn.mill.core.utils.NormUtil;

public class InvokeHandler implements InvocationHandler {
	
	private static Logger logger = LoggerFactory.getLogger(InvokeHandler.class);
	
	private Class<?> cless;
	
	public InvokeHandler(Class<?> cless) {
		this.cless = cless;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		logger.debug("=======invoke start==========================================");
		long start = System.currentTimeMillis();
		DefaultContext defaultContext = new DefaultContext();
		MethodMapping methodMapping = method.getAnnotation(MethodMapping.class);
		ServiceDefine serviceState = this.cless.getAnnotation(ServiceDefine.class);
		logger.debug("Method:" + method.getName());
		Node node = MillConfig.getNode(serviceState.node());
		
		Protocol protocol = MillConfig.getProtocol(NormUtil.isEmpty(serviceState.protocol()) ? node.protocol() : serviceState.protocol());
		Strategy strategy = MillConfig.getStrategy(NormUtil.isEmpty(methodMapping.strategy()) ? serviceState.strategy() : methodMapping.strategy());
		
		logger.debug("Protocol[" + protocol.getClass() + "]");
		logger.debug("Strategy[" + strategy.getClass() + "]");
		
		String value = NormUtil.isEmpty(methodMapping.value()) ? methodMapping.path() : methodMapping.value();
		
		defaultContext.setTip(methodMapping.tip());
		defaultContext.setMethod(method);
		defaultContext.setMethodAnnotations(method.getAnnotations());
		defaultContext.setParameterAnnotations(method.getParameterAnnotations());
		defaultContext.setParameters(args);
		defaultContext.setParameterTypes(method.getParameterTypes());
		defaultContext.setReturnType(method.getGenericReturnType());
		defaultContext.setListener(new DefaultListener());
		defaultContext.setNode(node);
		// 解析参数
		ItemArray itemArray = DefaultSpell.INSTANCE.resolver(defaultContext);
		defaultContext.setMapping(NormUtil.placeHolder(value, defaultContext.getAttachments()));
		// 构建报文
		Message<?> inputMessage = strategy.write(defaultContext, itemArray);
		// 调用
		Message<?> message = protocol.invoker(defaultContext, inputMessage);
		// 读取返回报文
		DataCommon<ItemArray> dataCommon = strategy.read(defaultContext, message);
		// 组建返回结果
		Object object = DefaultSpell.INSTANCE.builder(defaultContext.getReturnType(), dataCommon);
		long time = System.currentTimeMillis() - start;
		defaultContext.getListener().notify(defaultContext, time);
		logger.debug("=======invoke end ==========================================");
		return object;
	}
	
}
